home *** CD-ROM | disk | FTP | other *** search
/ InterCD 2000 September / september_2000.iso / intercd / root / ^Linux / cdrtools-1.10 / libhfs_iso / hfs.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-03-06  |  44.2 KB  |  2,148 lines

  1. /*
  2.  * hfsutils - tools for reading and writing Macintosh HFS volumes
  3.  * Copyright (C) 1996, 1997 Robert Leslie
  4.  *
  5.  * This program is free software; you can redistribute it and/or modify
  6.  * it under the terms of the GNU General Public License as published by
  7.  * the Free Software Foundation; either version 2 of the License, or
  8.  * (at your option) any later version.
  9.  *
  10.  * This program is distributed in the hope that it will be useful,
  11.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13.  * GNU General Public License for more details.
  14.  *
  15.  * You should have received a copy of the GNU General Public License
  16.  * along with this program; if not, write to the Free Software
  17.  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  18.  */
  19.  
  20. /* APPLE_HYB James Pearson j.pearson@ps.ucl.ac.uk 16/7/97 */
  21.  
  22. #include <mconfig.h>
  23. #include <stdxlib.h>
  24. #include <unixstd.h>
  25. #include <fcntl.h>
  26. #include <errno.h>
  27. #include <strdefs.h>
  28. #include <time.h>
  29. #include <ctype.h>
  30. #include <sys/stat.h>
  31.  
  32. #include "internal.h"
  33. #include "data.h"
  34. #include "block.h"
  35. #include "low.h"
  36. #include "file.h"
  37. #include "btree.h"
  38. #include "node.h"
  39. #include "record.h"
  40. #include "volume.h"
  41.  
  42. char *hfs_error = "no error";    /* static error string */
  43.  
  44. hfsvol *hfs_mounts;        /* linked list of mounted volumes */
  45. hfsvol *hfs_curvol;        /* current volume */
  46.  
  47. /* High-Level Volume Routines ============================================== */
  48.  
  49. /*
  50.  * NAME:    hfs->mount()
  51.  * DESCRIPTION:    open an HFS volume; return volume descriptor or 0 (error)
  52.  */
  53. #ifdef APPLE_HYB
  54. hfsvol *hfs_mount(hce, pnum, flags)
  55.     hce_mem    *hce;
  56.     int    pnum;
  57.     int    flags;
  58. #else
  59. hfsvol *hfs_mount(path, pnum, flags)
  60.     char    *path;
  61.     int    pnum;
  62.     int    flags;
  63. #endif /* APPLE_HYB */
  64. {
  65. #ifndef APPLE_HYB
  66.   struct stat dev;
  67. #endif
  68.   hfsvol *vol = 0;
  69.  
  70. #ifndef APPLE_HYB
  71.   /* see if the volume is already mounted */
  72.  
  73.   if (stat(path, &dev) >= 0)
  74.     {
  75.       struct stat mdev;
  76.       hfsvol *check;
  77.  
  78.       for (check = hfs_mounts; check; check = check->next)
  79.     {
  80.       if (fstat(check->fd, &mdev) >= 0 &&
  81.           mdev.st_dev == dev.st_dev &&
  82.           mdev.st_ino == dev.st_ino &&
  83.           (check->pnum == 0 || check->pnum == pnum))
  84.         {
  85.           /* verify compatible read/write mode */
  86.  
  87.           if (((check->flags & HFS_READONLY) &&
  88.            ! (flags & O_WRONLY)) ||
  89.           (! (check->flags & HFS_READONLY) &&
  90.            (flags & (O_WRONLY | O_RDWR))))
  91.         {
  92.           vol = check;
  93.           break;
  94.         }
  95.         }
  96.     }
  97.     }
  98. #endif /* APPLE_HYB */
  99.   if (vol == 0)
  100.     {
  101.       vol = ALLOC(hfsvol, 1);
  102.       if (vol == 0)
  103.     {
  104.       ERROR(ENOMEM, 0);
  105.       return 0;
  106.     }
  107.  
  108.       vol->flags  = 0;
  109.       vol->pnum   = pnum;
  110.       vol->vstart = 0;
  111.       vol->vlen   = 0;
  112.       vol->lpa    = 0;
  113.       vol->vbm    = 0;
  114.       vol->cwd    = HFS_CNID_ROOTDIR;
  115.  
  116.       vol->refs   = 0;
  117.       vol->files  = 0;
  118.       vol->dirs   = 0;
  119.       vol->prev   = 0;
  120.       vol->next   = 0;
  121.  
  122.       vol->ext.map     = 0;
  123.       vol->ext.mapsz   = 0;
  124.       vol->ext.flags   = 0;
  125.       vol->ext.compare = r_compareextkeys;
  126.  
  127.       vol->cat.map     = 0;
  128.       vol->cat.mapsz   = 0;
  129.       vol->cat.flags   = 0;
  130.       vol->cat.compare = r_comparecatkeys;
  131.  
  132.       /* open and lock the device */
  133.  
  134. #ifdef APPLE_HYB
  135.       vol->fd = 3;            /* any +ve number will do? */
  136.       vol->hce = hce;            /* store the extra with the vol info */
  137. #else
  138.       if (flags & (O_WRONLY | O_RDWR))
  139.     {
  140.       vol->fd = open(path, O_RDWR);
  141.       if (vol->fd >= 0 && l_lockvol(vol) < 0)
  142.         {
  143.           close(vol->fd);
  144.           vol->fd = -2;
  145.         }
  146.     }
  147.  
  148.       if (! (flags & (O_WRONLY | O_RDWR)) ||
  149.       (vol->fd < 0 &&
  150.        (errno == EROFS || errno == EACCES || errno == EAGAIN) &&
  151.        (flags & O_RDWR)))
  152.     {
  153.       vol->flags |= HFS_READONLY;
  154.       vol->fd = open(path, O_RDONLY);
  155.       if (vol->fd >= 0 && l_lockvol(vol) < 0)
  156.         {
  157.           close(vol->fd);
  158.           vol->fd = -2;
  159.         }
  160.     }
  161.  
  162.       if (vol->fd < 0)
  163.     {
  164.       if (vol->fd != -2)
  165.         ERROR(errno, "error opening device");
  166.  
  167.       v_destruct(vol);
  168.  
  169.       return 0;
  170.     }
  171. #endif /* APPLE_HYB */
  172.  
  173.       /* find out what kind of media this is and read the MDB */
  174.  
  175.       if (l_readblock0(vol) < 0 ||
  176.       l_readmdb(vol) < 0)
  177.     {
  178. #ifndef APPLE_HYB
  179.       close(vol->fd);
  180.       v_destruct(vol);
  181. #endif /* APPLE_HYB */
  182.       return 0;
  183.     }
  184.  
  185.       /* verify this is an HFS volume */
  186.  
  187.       if (vol->mdb.drSigWord != 0x4244)
  188.     {
  189. #ifndef APPLE_HYB
  190.       close(vol->fd);
  191. #endif /* APPLE_HYB */
  192.       v_destruct(vol);
  193.  
  194.       ERROR(EINVAL, "not a Macintosh HFS volume");
  195.       return 0;
  196.     }
  197.  
  198.       /* do minimal consistency checks */
  199.  
  200.       if (vol->mdb.drAlBlkSiz % HFS_BLOCKSZ != 0)
  201.     {
  202. #ifndef APPLE_HYB
  203.       close(vol->fd);
  204. #endif /* APPLE_HYB */
  205.       v_destruct(vol);
  206.  
  207.       ERROR(EINVAL, "bad volume allocation block size");
  208.       return 0;
  209.     }
  210.  
  211.       if (vol->vlen == 0)
  212.     vol->vlen = vol->mdb.drAlBlSt +
  213.       vol->mdb.drNmAlBlks * (vol->mdb.drAlBlkSiz / HFS_BLOCKSZ) + 2;
  214.  
  215.       /* read the volume bitmap and extents/catalog B*-tree headers */
  216.  
  217.       if (l_readvbm(vol) < 0 ||
  218.       bt_readhdr(&vol->ext) < 0 ||
  219.       bt_readhdr(&vol->cat) < 0)
  220.     {
  221. #ifndef APPLE_HYB
  222.       close(vol->fd);
  223. #endif /* APPLE_HYB */
  224.       v_destruct(vol);
  225.       return 0;
  226.     }
  227.  
  228.       if (! (vol->mdb.drAtrb & HFS_ATRB_UMOUNTED))
  229.     {
  230.       /* volume was not cleanly unmounted; scavenge free-space */
  231.  
  232.       if (v_scavenge(vol) < 0)
  233.         {
  234. #ifndef APPLE_HYB
  235.           close(vol->fd);
  236. #endif /* APPLE_HYB */
  237.           v_destruct(vol);
  238.           return 0;
  239.         }
  240.     }
  241.  
  242.       if (vol->flags & HFS_READONLY)
  243.     vol->mdb.drAtrb |= HFS_ATRB_HLOCKED;
  244.       else
  245.     vol->mdb.drAtrb &= ~HFS_ATRB_HLOCKED;
  246.  
  247.       vol->prev = 0;
  248.       vol->next = hfs_mounts;
  249.  
  250.       if (hfs_mounts)
  251.     hfs_mounts->prev = vol;
  252.  
  253.       hfs_mounts = vol;
  254.     }
  255.  
  256.   ++vol->refs;
  257.  
  258.   return hfs_curvol = vol;
  259. }
  260.  
  261. /*
  262.  * NAME:    hfs->flush()
  263.  * DESCRIPTION:    flush all pending changes to an HFS volume
  264.  */
  265. int hfs_flush(vol)
  266.     hfsvol    *vol;
  267. {
  268.   hfsfile *file;
  269.  
  270.   if (v_getvol(&vol) < 0)
  271.     return -1;
  272.  
  273.   for (file = vol->files; file; file = file->next)
  274.     {
  275.       if (f_flush(file) < 0)
  276.     return -1;
  277.     }
  278.  
  279.   if (v_flush(vol, 0) < 0)
  280.     return -1;
  281.  
  282.   return 0;
  283. }
  284.  
  285. /*
  286.  * NAME:    hfs->flushall()
  287.  * DESCRIPTION:    flush all pending changes to all mounted HFS volumes
  288.  */
  289. void hfs_flushall()
  290. {
  291.   hfsvol *vol;
  292.  
  293.   for (vol = hfs_mounts; vol; vol = vol->next)
  294.     hfs_flush(vol);
  295. }
  296.  
  297. /*
  298.  * NAME:    hfs->umount()
  299.  * DESCRIPTION:    close an HFS volume
  300.  */
  301. #ifdef APPLE_HYB
  302. /* extra argument used to alter the position of the extents/catalog files */
  303. int hfs_umount(vol, end)
  304.     hfsvol    *vol;
  305.     long    end;
  306. #else
  307. int hfs_umount(vol)
  308.     hfsvol    *vol;
  309. #endif /* APPLE_HYB */
  310. {
  311.   int result = 0;
  312.  
  313.   if (v_getvol(&vol) < 0)
  314.     return -1;
  315.  
  316.   if (--vol->refs)
  317.     return v_flush(vol, 0);
  318.  
  319.   /* close all open files and directories */
  320.  
  321.   while (vol->files)
  322. #ifdef APPLE_HYB
  323.     hfs_close(vol->files, 0, 0);
  324. #else
  325.     hfs_close(vol->files);
  326. #endif /* APPLE_HYB */
  327.  
  328.   while (vol->dirs)
  329.     hfs_closedir(vol->dirs);
  330.  
  331. #ifdef APPLE_HYB
  332.   if (end)
  333.   {
  334.     /*  move extents and catalog to end of volume ... */
  335.       long vbmsz = (vol->vlen / vol->lpa + 4095) / 4096;
  336.  
  337.     /* we are adding this "files" to the end of the ISO volume,
  338.        so calculate this address in HFS speak ... */
  339. /*    end -= vol->mdb.drAlBlSt; */
  340.     end -= (vol->mdb.drAlBlSt + vol->hce->hfs_map_size);
  341.     end /= vol->lpa;
  342.  
  343.     /* catalog file ... */
  344.     vol->ext.f.cat.u.fil.filExtRec[0].xdrStABN = end;
  345.      vol->mdb.drXTExtRec[0].xdrStABN = end;
  346.  
  347.     /* move postition to start of extents file */
  348.     end += vol->cat.f.cat.u.fil.filExtRec[0].xdrStABN;
  349.  
  350.     /* extents file ... */
  351.     vol->cat.f.cat.u.fil.filExtRec[0].xdrStABN = end;
  352.     vol->mdb.drCTExtRec[0].xdrStABN = end;
  353.  
  354.     /* the volume bitmap is wrong as we have "moved" files
  355.        about - simple just set the whole lot (it's a readonly volume
  356.        anyway!) */
  357.     memset(vol->vbm, 0xff, vbmsz*HFS_BLOCKSZ);
  358.  
  359.     /* set the free blocks to zero */
  360.     vol->mdb.drFreeBks = 0;
  361.  
  362.     /* flag changes for flushing later */
  363.     vol->flags |= HFS_UPDATE_VBM;
  364.     vol->flags |= HFS_UPDATE_MDB;
  365.     vol->mdb.drAtrb |= HFS_ATRB_HLOCKED;
  366.     vol->ext.flags |= HFS_UPDATE_BTHDR;
  367.     vol->cat.flags |= HFS_UPDATE_BTHDR;
  368.   }
  369. #endif /* APPLE_HYB */
  370.  
  371.   if (v_flush(vol, 1) < 0)
  372.     result = -1;
  373.  
  374. #ifndef APPLE_HYB
  375.   if (close(vol->fd) < 0 && result == 0)
  376.     {
  377.       ERROR(errno, "error closing device");
  378.       result = -1;
  379.     }
  380. #endif /* APPLE_HYB */
  381.  
  382.   if (vol->prev)
  383.     vol->prev->next = vol->next;
  384.   if (vol->next)
  385.     vol->next->prev = vol->prev;
  386.  
  387.   if (vol == hfs_mounts)
  388.     hfs_mounts = vol->next;
  389.   if (vol == hfs_curvol)
  390.     hfs_curvol = 0;
  391.  
  392.   v_destruct(vol);
  393.  
  394.   return result;
  395. }
  396.  
  397. /*
  398.  * NAME:    hfs->umountall()
  399.  * DESCRIPTION:    unmount all mounted volumes
  400.  */
  401. void hfs_umountall()
  402. {
  403.   while (hfs_mounts)
  404. #ifdef APPLE_HYB
  405.     continue;
  406. #else
  407.     hfs_umount(hfs_mounts);
  408. #endif /* APPLE_HYB */
  409. }
  410.  
  411. /*
  412.  * NAME:    hfs->getvol()
  413.  * DESCRIPTION:    return a pointer to a mounted volume
  414.  */
  415. hfsvol *hfs_getvol(name)
  416.     char    *name;
  417. {
  418.   hfsvol *vol;
  419.  
  420.   if (name == 0)
  421.     return hfs_curvol;
  422.  
  423.   for (vol = hfs_mounts; vol; vol = vol->next)
  424.     {
  425.       if (d_relstring(name, vol->mdb.drVN) == 0)
  426.     return vol;
  427.     }
  428.  
  429.   return 0;
  430. }
  431.  
  432. /*
  433.  * NAME:    hfs->setvol()
  434.  * DESCRIPTION:    change the current volume
  435.  */
  436. void hfs_setvol(vol)
  437.     hfsvol    *vol;
  438. {
  439.   hfs_curvol = vol;
  440. }
  441.  
  442. /*
  443.  * NAME:    hfs->vstat()
  444.  * DESCRIPTION:    return volume statistics
  445.  */
  446. int hfs_vstat(vol, ent)
  447.     hfsvol    *vol;
  448.     hfsvolent *ent;
  449. {
  450.   if (v_getvol(&vol) < 0)
  451.     return -1;
  452.  
  453.   strcpy(ent->name, vol->mdb.drVN);
  454.  
  455.   ent->flags     = (vol->flags & HFS_READONLY) ? HFS_ISLOCKED : 0;
  456.   ent->totbytes  = vol->mdb.drNmAlBlks * vol->mdb.drAlBlkSiz;
  457.   ent->freebytes = vol->mdb.drFreeBks  * vol->mdb.drAlBlkSiz;
  458.   ent->crdate    = d_toutime(vol->mdb.drCrDate);
  459.   ent->mddate    = d_toutime(vol->mdb.drLsMod);
  460.  
  461.   return 0;
  462. }
  463.  
  464. /*
  465.  * NAME:    hfs->format()
  466.  * DESCRIPTION:    write a new filesystem
  467.  */
  468. #ifdef APPLE_HYB
  469. int hfs_format(hce, pnum, vname)
  470.     hce_mem    *hce;
  471.     int    pnum;
  472.     char    *vname;
  473. #else
  474. int hfs_format(path, pnum, vname)
  475.     char    *path;
  476.     int    pnum;
  477.     char    *vname;
  478. #endif /* APPLE_HYB */
  479. {
  480.   hfsvol vol;
  481.   btree *ext = &vol.ext;
  482.   btree *cat = &vol.cat;
  483.   unsigned int vbmsz;
  484.   int i, result = 0;
  485.   block vbm[16];
  486.   char *map;
  487.  
  488.   if (strchr(vname, ':'))
  489.     {
  490.       ERROR(EINVAL, "volume name may not contain colons");
  491.       return -1;
  492.     }
  493.  
  494.   i = strlen(vname);
  495.   if (i < 1 || i > HFS_MAX_VLEN)
  496.     {
  497.       ERROR(EINVAL, "volume name must be 1-27 chars");
  498.       return -1;
  499.     }
  500.  
  501.   vol.flags  = 0;
  502.   vol.pnum   = pnum;
  503.   vol.vstart = 0;
  504.   vol.vlen   = 0;
  505.   vol.lpa    = 0;
  506.   vol.vbm    = vbm;
  507.   vol.cwd    = HFS_CNID_ROOTDIR;
  508.  
  509.   vol.refs   = 0;
  510.   vol.files  = 0;
  511.   vol.dirs   = 0;
  512.   vol.prev   = 0;
  513.   vol.next   = 0;
  514.  
  515. #ifndef APPLE_HYB
  516.   vol.fd = open(path, O_RDWR);
  517.   if (vol.fd < 0)
  518.     {
  519.       ERROR(errno, "error opening device for writing");
  520.       return -1;
  521.     }
  522.  
  523.   if (l_lockvol(&vol) < 0)
  524.     {
  525.       close(vol.fd);
  526.       return -1;
  527.     }
  528. #endif /* APPLE_HYB */
  529.   if (pnum > 0)
  530.     {
  531.       if (l_readpm(&vol) < 0)
  532.     {
  533.       close(vol.fd);
  534.       return -1;
  535.     }
  536.     }
  537.   else  /* determine size of entire device */
  538.     {
  539. #ifdef APPLE_HYB
  540.       vol.vlen = hce->hfs_vol_size/HFS_BLOCKSZ;
  541. #else
  542.       unsigned long low, high, mid;
  543.       block b;
  544.  
  545.       for (low = 0, high = 2879; b_readlb(&vol, high, &b) >= 0; high *= 2)
  546.     low = high;
  547.  
  548.       while (low < high - 1)
  549.     {
  550.       mid = (low + high) / 2;
  551.  
  552.       if (b_readlb(&vol, mid, &b) < 0)
  553.         high = mid;
  554.       else
  555.         low = mid;
  556.     }
  557.  
  558.       vol.vlen = low + 1;
  559. #endif /* APPLE_HYB */
  560.     }
  561.  
  562.   if (vol.vlen < 800 * 1024 / HFS_BLOCKSZ)
  563.     {
  564. #ifndef APPLE_HYB
  565.       close(vol.fd);
  566. #endif /* APPLE_HYB */
  567.  
  568.       ERROR(EINVAL, "volume size must be >= 800K");
  569.       return -1;
  570.     }
  571.  
  572.   /* initialize volume geometry */
  573.  
  574. #ifdef APPLE_HYB
  575.   /* force lpa to be a multiple of 4 (i.e. 2048/512) - as calculated 
  576.      earlier */
  577.   vol.lpa = hce->Csize/HFS_BLOCKSZ;
  578. #else
  579.   vol.lpa = 1 + vol.vlen / 65536;
  580. #endif /* APPLE_HYB */
  581.  
  582.   vbmsz = (vol.vlen / vol.lpa + 4095) / 4096;
  583.  
  584.   vol.mdb.drSigWord  = 0x4244;
  585.   vol.mdb.drCrDate   = d_tomtime(time(0));
  586.   vol.mdb.drLsMod    = vol.mdb.drCrDate;
  587.   vol.mdb.drAtrb     = 0;
  588.   vol.mdb.drNmFls    = 0;
  589.   vol.mdb.drVBMSt    = 3;
  590.   vol.mdb.drAllocPtr = 0;
  591.   vol.mdb.drNmAlBlks = (vol.vlen - 5 - vbmsz) / vol.lpa;
  592.   vol.mdb.drAlBlkSiz = vol.lpa * HFS_BLOCKSZ;
  593.   vol.mdb.drClpSiz   = vol.mdb.drAlBlkSiz * 4;
  594.   vol.mdb.drAlBlSt   = 3 + vbmsz;
  595. #ifdef APPLE_HYB
  596.   /* round up start block to a muliple of lpa - important later */
  597. /*vol.mdb.drAlBlSt   = ((vol.mdb.drAlBlSt + vol.lpa -  1) / vol.lpa) * vol.lpa; 
  598. */
  599.   /* take in accout alignment of files wrt HFS volume start i.e we want
  600.      drAlBlSt plus hfs_map_size to me a multiple of lpa */
  601.   vol.mdb.drAlBlSt   = ((vol.mdb.drAlBlSt + hce->hfs_map_size + vol.lpa -  1) / vol.lpa) * vol.lpa; 
  602.   vol.mdb.drAlBlSt   -= hce->hfs_map_size;
  603. #endif /* APPLE_HYB */
  604.   vol.mdb.drNxtCNID  = HFS_CNID_ROOTDIR;  /* modified later */
  605.   vol.mdb.drFreeBks  = vol.mdb.drNmAlBlks;
  606.  
  607.   strcpy(vol.mdb.drVN, vname);
  608.  
  609.   vol.mdb.drVolBkUp  = 0;
  610.   vol.mdb.drVSeqNum  = 0;
  611.   vol.mdb.drWrCnt    = 0;
  612.   vol.mdb.drXTClpSiz = vol.mdb.drNmAlBlks / 128 * vol.mdb.drAlBlkSiz;
  613. #ifdef APPLE_HYB
  614.   /* adjust size of extents/catalog upwards as we may have rounded up
  615.      allocation size */
  616.   i = 1 + vol.vlen / 65536;
  617.  
  618.   vol.mdb.drXTClpSiz = (vol.mdb.drXTClpSiz * vol.lpa) / i;
  619.  
  620.   /* round up to lpa size */
  621.   vol.mdb.drXTClpSiz = ((vol.mdb.drXTClpSiz + vol.mdb.drAlBlkSiz - 1) /
  622.                 vol.mdb.drAlBlkSiz) * vol.mdb.drAlBlkSiz;
  623.  
  624.   /* ignore above, use what we have already calculated ... */
  625.   vol.mdb.drXTClpSiz = hce->XTCsize;
  626.  
  627.   /* make Catalog file CTC (default twice) as big - prevents further allocation
  628.      later which we don't want - this seems to work OK ... */
  629. /*vol.mdb.drCTClpSiz = vol.mdb.drXTClpSiz * CTC; */
  630.   vol.mdb.drCTClpSiz = vol.mdb.drXTClpSiz * hce->ctc_size;
  631.  
  632.   /* we want to put things at the end of the volume later, so we'll
  633.      cheat here ... shouldn't matter, as we only need the volume read
  634.      only anyway (we won't be adding files later!) - leave some extra
  635.      space for the alternative MDB (in the last allocation block) */
  636.  
  637.   vol.mdb.drNmAlBlks = vol.mdb.drFreeBks = vol.vlen / vol.lpa - 1;
  638. #else
  639.   vol.mdb.drCTClpSiz = vol.mdb.drXTClpSiz;
  640. #endif /* APPLE_HYB */
  641.   vol.mdb.drNmRtDirs = 0;
  642.   vol.mdb.drFilCnt   = 0;
  643.   vol.mdb.drDirCnt   = -1;  /* incremented when root folder is created */
  644.  
  645.   for (i = 0; i < 8; ++i)
  646.     vol.mdb.drFndrInfo[i] = 0;
  647.  
  648.   vol.mdb.drVCSize   = 0;
  649.   vol.mdb.drVBMCSize = 0;
  650.   vol.mdb.drCtlCSize = 0;
  651.  
  652.   vol.mdb.drXTFlSize = 0;
  653.   vol.mdb.drCTFlSize = 0;
  654.  
  655.   for (i = 0; i < 3; ++i)
  656.     {
  657.       vol.mdb.drXTExtRec[i].xdrStABN    = 0;
  658.       vol.mdb.drXTExtRec[i].xdrNumABlks = 0;
  659.  
  660.       vol.mdb.drCTExtRec[i].xdrStABN    = 0;
  661.       vol.mdb.drCTExtRec[i].xdrNumABlks = 0;
  662.     }
  663.  
  664.   /* initialize volume bitmap */
  665.  
  666.   memset(vol.vbm, 0, sizeof(vbm));
  667.  
  668. #ifdef APPLE_HYB
  669.   /* We don't want to write anything out at the moment, so we allocate
  670.      memory to hold the HFS "header" info and extents/catalog files.
  671.      Any reads/writes from/to these parts of the volume are trapped and
  672.      stored in memory. */
  673.  
  674.   /* blocks up to the first unallocated block == HFS "header" info
  675.      This will be placed in the first 32kb of the ISO volume later */
  676.   hce->hfs_hdr_size = vol.mdb.drAlBlSt;
  677.  
  678.   /* size of the extents and catalog files. This will be added
  679.      to the end of the ISO volume later */
  680.   hce->hfs_ce_size =  vol.mdb.drXTClpSiz + vol.mdb.drCTClpSiz;
  681.  
  682.   /* we also allocate space for the Desktop file and the alternative
  683.      MDB while we're here */
  684.   FREE(hce->hfs_ce);
  685.   hce->hfs_ce = ALLOC(unsigned char, (hce->hfs_ce_size + vol.mdb.drClpSiz
  686.                     + vol.mdb.drAlBlkSiz));
  687.  
  688.   /* allocate memory for the map and hdr */
  689.   FREE(hce->hfs_map);
  690.   hce->hfs_map = ALLOC(unsigned char, ((hce->hfs_hdr_size + hce->hfs_map_size)
  691.             *HFS_BLOCKSZ));
  692.  
  693.   if (hce->hfs_ce == 0 || hce->hfs_map == 0)
  694.     {
  695.       ERROR(ENOMEM, 0);
  696.       result = -1;
  697.     }
  698.  
  699.   /* hfs_hdr is immediately after the hfs_map */
  700.   hce->hfs_hdr = hce->hfs_map + hce->hfs_map_size*HFS_BLOCKSZ;
  701.  
  702.   /* size needed in HFS_BLOCKSZ blocks for later use */
  703.   hce->hfs_ce_size /= HFS_BLOCKSZ;
  704.  
  705.   /* note size of Desktop file */
  706.   hce->hfs_dt_size = vol.mdb.drClpSiz/HFS_BLOCKSZ;
  707.  
  708.   /* total size of catalog/extents and desktop */
  709.   hce->hfs_tot_size = hce->hfs_ce_size + hce->hfs_dt_size;
  710.  
  711.   /* alternative MDB in the last alocation block */
  712.   hce->hfs_alt_mdb = hce->hfs_ce + hce->hfs_tot_size*HFS_BLOCKSZ;
  713.  
  714.   /* add the MDB to the total size */
  715.   hce->hfs_tot_size += vol.lpa;
  716.  
  717.   /* store this info in the volume info */
  718.   vol.hce = hce;
  719.  
  720. #endif /* APPLE_HYB */
  721.  
  722.   /* create extents overflow file */
  723.  
  724.   ext->f.vol   = &vol;
  725.   ext->f.parid = 0;
  726.   strcpy(ext->f.name, "extents overflow");
  727.  
  728.   ext->f.cat.cdrType          = cdrFilRec;
  729.   /* ext->f.cat.cdrResrv2 */
  730.   ext->f.cat.u.fil.filFlags   = 0;
  731.   ext->f.cat.u.fil.filTyp     = 0;
  732.   /* ext->f.cat.u.fil.filUsrWds */
  733.   ext->f.cat.u.fil.filFlNum   = HFS_CNID_EXT;
  734.   ext->f.cat.u.fil.filStBlk   = 0;
  735.   ext->f.cat.u.fil.filLgLen   = 0;
  736.   ext->f.cat.u.fil.filPyLen   = 0;
  737.   ext->f.cat.u.fil.filRStBlk  = 0;
  738.   ext->f.cat.u.fil.filRLgLen  = 0;
  739.   ext->f.cat.u.fil.filRPyLen  = 0;
  740.   ext->f.cat.u.fil.filCrDat   = vol.mdb.drCrDate;
  741.   ext->f.cat.u.fil.filMdDat   = vol.mdb.drLsMod;
  742.   ext->f.cat.u.fil.filBkDat   = 0;
  743.   /* ext->f.cat.u.fil.filFndrInfo */
  744.   ext->f.cat.u.fil.filClpSize = 0;
  745.  
  746.   for (i = 0; i < 3; ++i)
  747.     {
  748.       ext->f.cat.u.fil.filExtRec[i].xdrStABN     = 0;
  749.       ext->f.cat.u.fil.filExtRec[i].xdrNumABlks  = 0;
  750.  
  751.       ext->f.cat.u.fil.filRExtRec[i].xdrStABN    = 0;
  752.       ext->f.cat.u.fil.filRExtRec[i].xdrNumABlks = 0;
  753.     }
  754.   /* ext->f.cat.u.fil.filResrv */
  755.   f_selectfork(&ext->f, 0);
  756.  
  757.   ext->f.clump = vol.mdb.drXTClpSiz;
  758.   ext->f.flags = 0;
  759.  
  760.   ext->f.prev = ext->f.next = 0;
  761.  
  762.   n_init(&ext->hdrnd, ext, ndHdrNode, 0);
  763.  
  764.   ext->hdrnd.nnum       = 0;
  765.   ext->hdrnd.nd.ndNRecs = 3;
  766.   ext->hdrnd.roff[1]    = 0x078;
  767.   ext->hdrnd.roff[2]    = 0x0f8;
  768.   ext->hdrnd.roff[3]    = 0x1f8;
  769.  
  770.   memset(HFS_NODEREC(ext->hdrnd, 1), 0, 128);
  771.  
  772.   ext->hdr.bthDepth    = 0;
  773.   ext->hdr.bthRoot     = 0;
  774.   ext->hdr.bthNRecs    = 0;
  775.   ext->hdr.bthFNode    = 0;
  776.   ext->hdr.bthLNode    = 0;
  777.   ext->hdr.bthNodeSize = HFS_BLOCKSZ;
  778.   ext->hdr.bthKeyLen   = 0x07;
  779.   ext->hdr.bthNNodes   = 0;
  780.   ext->hdr.bthFree     = 0;
  781.   for (i = 0; i < 76; ++i)
  782.     ext->hdr.bthResv[i] = 0;
  783.  
  784.   map = ALLOC(char, HFS_MAP1SZ);
  785.   if (map == 0)
  786.     {
  787.       if (result == 0)
  788.     {
  789.       ERROR(ENOMEM, 0);
  790.       result = -1;
  791.     }
  792.     }
  793.   else
  794.     {
  795.       memset(map, 0, HFS_MAP1SZ);
  796.       BMSET(map, 0);
  797.     }
  798.  
  799.   ext->map     = map;
  800.   ext->mapsz   = HFS_MAP1SZ;
  801.   ext->flags   = HFS_UPDATE_BTHDR;
  802.   ext->compare = r_compareextkeys;
  803.  
  804.   if (result == 0 && bt_space(ext, 1) < 0)
  805.     result = -1;
  806.  
  807.   --ext->hdr.bthFree;
  808.  
  809.   /* create catalog file */
  810.  
  811.   cat->f.vol   = &vol;
  812.   cat->f.parid = 0;
  813.   strcpy(cat->f.name, "catalog");
  814.  
  815.   cat->f.cat.cdrType          = cdrFilRec;
  816.   /* cat->f.cat.cdrResrv2 */
  817.   cat->f.cat.u.fil.filFlags   = 0;
  818.   cat->f.cat.u.fil.filTyp     = 0;
  819.   /* cat->f.cat.u.fil.filUsrWds */
  820.   cat->f.cat.u.fil.filFlNum   = HFS_CNID_CAT;
  821.   cat->f.cat.u.fil.filStBlk   = 0;
  822.   cat->f.cat.u.fil.filLgLen   = 0;
  823.   cat->f.cat.u.fil.filPyLen   = 0;
  824.   cat->f.cat.u.fil.filRStBlk  = 0;
  825.   cat->f.cat.u.fil.filRLgLen  = 0;
  826.   cat->f.cat.u.fil.filRPyLen  = 0;
  827.   cat->f.cat.u.fil.filCrDat   = vol.mdb.drCrDate;
  828.   cat->f.cat.u.fil.filMdDat   = vol.mdb.drLsMod;
  829.   cat->f.cat.u.fil.filBkDat   = 0;
  830.   /* cat->f.cat.u.fil.filFndrInfo */
  831.   cat->f.cat.u.fil.filClpSize = 0;
  832.  
  833.   for (i = 0; i < 3; ++i)
  834.     {
  835.       cat->f.cat.u.fil.filExtRec[i].xdrStABN     = 0;
  836.       cat->f.cat.u.fil.filExtRec[i].xdrNumABlks  = 0;
  837.  
  838.       cat->f.cat.u.fil.filRExtRec[i].xdrStABN    = 0;
  839.       cat->f.cat.u.fil.filRExtRec[i].xdrNumABlks = 0;
  840.     }
  841.   /* cat->f.cat.u.fil.filResrv */
  842.   f_selectfork(&cat->f, 0);
  843.  
  844.   cat->f.clump = vol.mdb.drCTClpSiz;
  845.   cat->f.flags = 0;
  846.  
  847.   cat->f.prev = cat->f.next = 0;
  848.  
  849.   n_init(&cat->hdrnd, cat, ndHdrNode, 0);
  850.  
  851.   cat->hdrnd.nnum       = 0;
  852.   cat->hdrnd.nd.ndNRecs = 3;
  853.   cat->hdrnd.roff[1]    = 0x078;
  854.   cat->hdrnd.roff[2]    = 0x0f8;
  855.   cat->hdrnd.roff[3]    = 0x1f8;
  856.  
  857.   memset(HFS_NODEREC(cat->hdrnd, 1), 0, 128);
  858.  
  859.   cat->hdr.bthDepth    = 0;
  860.   cat->hdr.bthRoot     = 0;
  861.   cat->hdr.bthNRecs    = 0;
  862.   cat->hdr.bthFNode    = 0;
  863.   cat->hdr.bthLNode    = 0;
  864.   cat->hdr.bthNodeSize = HFS_BLOCKSZ;
  865.   cat->hdr.bthKeyLen   = 0x25;
  866.   cat->hdr.bthNNodes   = 0;
  867.   cat->hdr.bthFree     = 0;
  868.   for (i = 0; i < 76; ++i)
  869.     cat->hdr.bthResv[i] = 0;
  870.  
  871.   map = ALLOC(char, HFS_MAP1SZ);
  872.   if (map == 0)
  873.     {
  874.       if (result == 0)
  875.     {
  876.       ERROR(ENOMEM, 0);
  877.       result = -1;
  878.     }
  879.     }
  880.   else
  881.     {
  882.       memset(map, 0, HFS_MAP1SZ);
  883.       BMSET(map, 0);
  884.     }
  885.  
  886.   cat->map     = map;
  887.   cat->mapsz   = HFS_MAP1SZ;
  888.   cat->flags   = HFS_UPDATE_BTHDR;
  889.   cat->compare = r_comparecatkeys;
  890.  
  891.   if (result == 0 && bt_space(cat, 1) < 0)
  892.     result = -1;
  893.  
  894.   --cat->hdr.bthFree;
  895.  
  896.   /* create root folder */
  897.  
  898.   if (result == 0 && v_newfolder(&vol, HFS_CNID_ROOTPAR, vname) < 0)
  899.     result = -1;
  900.  
  901.   vol.mdb.drNxtCNID = 16;
  902.  
  903.   /* finish up */
  904.  
  905.   if (result == 0)
  906.     {
  907.       block b;
  908.  
  909.       /* write boot blocks */
  910.  
  911.       memset(&b, 0, sizeof(b));
  912.       b_writelb(&vol, 0, &b);
  913.       b_writelb(&vol, 1, &b);
  914.  
  915.       /* flush other disk state */
  916.  
  917.       vol.flags |= HFS_UPDATE_MDB | HFS_UPDATE_ALTMDB | HFS_UPDATE_VBM;
  918.  
  919.       if (v_flush(&vol, 1) < 0)
  920.     result = -1;
  921.     }
  922. #ifndef APPLE_HYB
  923.   if (close(vol.fd) < 0 && result == 0)
  924.     {
  925.       ERROR(errno, "error closing device");
  926.       result = -1;
  927.     }
  928. #endif /* APPLE_HYB */
  929.   FREE(vol.ext.map);
  930.   FREE(vol.cat.map);
  931.  
  932.   return result;
  933. }
  934.  
  935. /* High-Level Directory Routines =========================================== */
  936.  
  937. /*
  938.  * NAME:    hfs->chdir()
  939.  * DESCRIPTION:    change current HFS directory
  940.  */
  941. int hfs_chdir(vol, path)
  942.     hfsvol    *vol;
  943.     char    *path;
  944. {
  945.   CatDataRec data;
  946.  
  947.   if (v_getvol(&vol) < 0 ||
  948.       v_resolve(&vol, path, &data, 0, 0, 0) <= 0)
  949.     return -1;
  950.  
  951.   if (data.cdrType != cdrDirRec)
  952.     {
  953.       ERROR(ENOTDIR, 0);
  954.       return -1;
  955.     }
  956.  
  957.   vol->cwd = data.u.dir.dirDirID;
  958.  
  959.   return 0;
  960. }
  961.  
  962. /*
  963.  * NAME:    hfs->getcwd()
  964.  * DESCRIPTION:    return the current working directory ID
  965.  */
  966. long hfs_getcwd(vol)
  967.     hfsvol    *vol;
  968. {
  969.   if (v_getvol(&vol) < 0)
  970.     return 0;
  971.  
  972.   return vol->cwd;
  973. }
  974.  
  975. /*
  976.  * NAME:    hfs->setcwd()
  977.  * DESCRIPTION:    set the current working directory ID
  978.  */
  979. int hfs_setcwd(vol, id)
  980.     hfsvol    *vol;
  981.     long    id;
  982. {
  983.   if (v_getvol(&vol) < 0)
  984.     return -1;
  985.  
  986.   if (id == vol->cwd)
  987.     return 0;
  988.  
  989.   /* make sure the directory exists */
  990.  
  991.   if (v_getdthread(vol, id, 0, 0) <= 0)
  992.     return -1;
  993.  
  994.   vol->cwd = id;
  995.  
  996.   return 0;
  997. }
  998.  
  999. /*
  1000.  * NAME:    hfs->dirinfo()
  1001.  * DESCRIPTION:    given a directory ID, return its (name and) parent ID
  1002.  */
  1003. int hfs_dirinfo(vol, id, name)
  1004.     hfsvol    *vol;
  1005.     long    *id;
  1006.     char    *name;
  1007. {
  1008.   CatDataRec thread;
  1009.  
  1010.   if (v_getvol(&vol) < 0 ||
  1011.       v_getdthread(vol, *id, &thread, 0) <= 0)
  1012.     return -1;
  1013.  
  1014.   *id = thread.u.dthd.thdParID;
  1015.  
  1016.   if (name)
  1017.     strcpy(name, thread.u.dthd.thdCName);
  1018.  
  1019.   return 0;
  1020. }
  1021.  
  1022. /*
  1023.  * NAME:    hfs->opendir()
  1024.  * DESCRIPTION:    prepare to read the contents of a directory
  1025.  */
  1026. hfsdir *hfs_opendir(vol, path)
  1027.     hfsvol    *vol;
  1028.     char    *path;
  1029. {
  1030.   hfsdir *dir;
  1031.   CatKeyRec key;
  1032.   CatDataRec data;
  1033.   unsigned char pkey[HFS_CATKEYLEN];
  1034.  
  1035.   if (v_getvol(&vol) < 0)
  1036.     return 0;
  1037.  
  1038.   dir = ALLOC(hfsdir, 1);
  1039.   if (dir == 0)
  1040.     {
  1041.       ERROR(ENOMEM, 0);
  1042.       return 0;
  1043.     }
  1044.  
  1045.   dir->vol = vol;
  1046.  
  1047.   if (*path == 0)
  1048.     {
  1049.       /* meta-directory containing root dirs from all mounted volumes */
  1050.  
  1051.       dir->dirid = 0;
  1052.       dir->vptr  = hfs_mounts;
  1053.     }
  1054.   else
  1055.     {
  1056.       if (v_resolve(&vol, path, &data, 0, 0, 0) <= 0)
  1057.     {
  1058.       FREE(dir);
  1059.       return 0;
  1060.     }
  1061.  
  1062.       if (data.cdrType != cdrDirRec)
  1063.     {
  1064.       FREE(dir);
  1065.       ERROR(ENOTDIR, 0);
  1066.       return 0;
  1067.     }
  1068.  
  1069.       dir->dirid = data.u.dir.dirDirID;
  1070.       dir->vptr  = 0;
  1071.  
  1072.       r_makecatkey(&key, dir->dirid, "");
  1073.       r_packcatkey(&key, pkey, 0);
  1074.  
  1075.       if (bt_search(&vol->cat, pkey, &dir->n) <= 0)
  1076.     {
  1077.       FREE(dir);
  1078.       return 0;
  1079.     }
  1080.     }
  1081.  
  1082.   dir->prev = 0;
  1083.   dir->next = vol->dirs;
  1084.  
  1085.   if (vol->dirs)
  1086.     vol->dirs->prev = dir;
  1087.  
  1088.   vol->dirs = dir;
  1089.  
  1090.   return dir;
  1091. }
  1092.  
  1093. /*
  1094.  * NAME:    hfs->readdir()
  1095.  * DESCRIPTION:    return the next entry in the directory
  1096.  */
  1097. int hfs_readdir(dir, ent)
  1098.     hfsdir    *dir;
  1099.     hfsdirent *ent;
  1100. {
  1101.   CatKeyRec key;
  1102.   CatDataRec data;
  1103.   unsigned char *ptr;
  1104.  
  1105.   if (dir->dirid == 0)
  1106.     {
  1107.       hfsvol *vol;
  1108.       char cname[HFS_MAX_FLEN + 1];
  1109.  
  1110.       for (vol = hfs_mounts; vol; vol = vol->next)
  1111.     {
  1112.       if (vol == dir->vptr)
  1113.         break;
  1114.     }
  1115.  
  1116.       if (vol == 0)
  1117.     {
  1118.       ERROR(ENOENT, "no more entries");
  1119.       return -1;
  1120.     }
  1121.  
  1122.       if (v_getdthread(vol, HFS_CNID_ROOTDIR, &data, 0) <= 0 ||
  1123.       v_catsearch(vol, HFS_CNID_ROOTPAR, data.u.dthd.thdCName,
  1124.               &data, cname, 0) < 0)
  1125.     return -1;
  1126.  
  1127.       r_unpackdirent(HFS_CNID_ROOTPAR, cname, &data, ent);
  1128.  
  1129.       dir->vptr = vol->next;
  1130.  
  1131.       return 0;
  1132.     }
  1133.  
  1134.   if (dir->n.rnum == -1)
  1135.     {
  1136.       ERROR(ENOENT, "no more entries");
  1137.       return -1;
  1138.     }
  1139.  
  1140.   while (1)
  1141.     {
  1142.       ++dir->n.rnum;
  1143.  
  1144.       while (dir->n.rnum >= dir->n.nd.ndNRecs)
  1145.     {
  1146.       dir->n.nnum = dir->n.nd.ndFLink;
  1147.       if (dir->n.nnum == 0)
  1148.         {
  1149.           dir->n.rnum = -1;
  1150.           ERROR(ENOENT, "no more entries");
  1151.           return -1;
  1152.         }
  1153.  
  1154.       if (bt_getnode(&dir->n) < 0)
  1155.         {
  1156.           dir->n.rnum = -1;
  1157.           return -1;
  1158.         }
  1159.  
  1160.       dir->n.rnum = 0;
  1161.     }
  1162.  
  1163.       ptr = HFS_NODEREC(dir->n, dir->n.rnum);
  1164.  
  1165.       r_unpackcatkey(ptr, &key);
  1166.  
  1167.       if (key.ckrParID != dir->dirid)
  1168.     {
  1169.       dir->n.rnum = -1;
  1170.       ERROR(ENOENT, "no more entries");
  1171.       return -1;
  1172.     }
  1173.  
  1174.       r_unpackcatdata(HFS_RECDATA(ptr), &data);
  1175.  
  1176.       switch (data.cdrType)
  1177.     {
  1178.     case cdrDirRec:
  1179.     case cdrFilRec:
  1180.       r_unpackdirent(key.ckrParID, key.ckrCName, &data, ent);
  1181.       return 0;
  1182.  
  1183.     case cdrThdRec:
  1184.     case cdrFThdRec:
  1185.       break;
  1186.  
  1187.     default:
  1188.       dir->n.rnum = -1;
  1189.  
  1190.       ERROR(EIO, "unexpected directory entry found");
  1191.       return -1;
  1192.     }
  1193.     }
  1194. }
  1195.  
  1196. /*
  1197.  * NAME:    hfs->closedir()
  1198.  * DESCRIPTION:    stop reading a directory
  1199.  */
  1200. int hfs_closedir(dir)
  1201.     hfsdir    *dir;
  1202. {
  1203.   hfsvol *vol = dir->vol;
  1204.  
  1205.   if (dir->prev)
  1206.     dir->prev->next = dir->next;
  1207.   if (dir->next)
  1208.     dir->next->prev = dir->prev;
  1209.   if (dir == vol->dirs)
  1210.     vol->dirs = dir->next;
  1211.  
  1212.   FREE(dir);
  1213.  
  1214.   return 0;
  1215. }
  1216.  
  1217. /* High-Level File Routines ================================================ */
  1218.  
  1219. /*
  1220.  * NAME:    hfs->open()
  1221.  * DESCRIPTION:    prepare a file for I/O
  1222.  */
  1223. hfsfile *hfs_open(vol, path)
  1224.     hfsvol    *vol;
  1225.     char    *path;
  1226. {
  1227.   hfsfile *file;
  1228.  
  1229.   if (v_getvol(&vol) < 0)
  1230.     return 0;
  1231.  
  1232.   file = ALLOC(hfsfile, 1);
  1233.   if (file == 0)
  1234.     {
  1235.       ERROR(ENOMEM, 0);
  1236.       return 0;
  1237.     }
  1238.  
  1239.   if (v_resolve(&vol, path, &file->cat, &file->parid, file->name, 0) <= 0)
  1240.     {
  1241.       FREE(file);
  1242.       return 0;
  1243.     }
  1244.  
  1245.   if (file->cat.cdrType != cdrFilRec)
  1246.     {
  1247.       FREE(file);
  1248.       ERROR(EISDIR, 0);
  1249.       return 0;
  1250.     }
  1251.  
  1252.   file->vol   = vol;
  1253.   file->clump = file->cat.u.fil.filClpSize;
  1254.   file->flags = 0;
  1255.  
  1256.   f_selectfork(file, 0);
  1257.  
  1258.   file->prev = 0;
  1259.   file->next = vol->files;
  1260.  
  1261.   if (vol->files)
  1262.     vol->files->prev = file;
  1263.  
  1264.   vol->files = file;
  1265.  
  1266.   return file;
  1267. }
  1268.  
  1269. /*
  1270.  * NAME:    hfs->setfork()
  1271.  * DESCRIPTION:    select file fork for I/O operations
  1272.  */
  1273. int hfs_setfork(file, ffork)
  1274.     hfsfile    *file;
  1275.     int    ffork;
  1276. {
  1277.   int result = 0;
  1278.  
  1279.   if (! (file->vol->flags & HFS_READONLY) &&
  1280.       f_trunc(file) < 0)
  1281.     result = -1;
  1282.  
  1283.   f_selectfork(file, ffork);
  1284.  
  1285.   return result;
  1286. }
  1287.  
  1288. /*
  1289.  * NAME:    hfs->getfork()
  1290.  * DESCRIPTION:    return the current fork for I/O operations
  1291.  */
  1292. int hfs_getfork(file)
  1293.     hfsfile    *file;
  1294. {
  1295.   return file->fork != fkData;
  1296. }
  1297.  
  1298. /*
  1299.  * NAME:    hfs->read()
  1300.  * DESCRIPTION:    read from an open file
  1301.  */
  1302. long hfs_read(file, buf, len)
  1303.     hfsfile        *file;
  1304.     void        *buf;
  1305.     unsigned long    len;
  1306. {
  1307.   unsigned long *lglen, count;
  1308.   unsigned char *ptr = buf;
  1309.  
  1310.   f_getptrs(file, &lglen, 0, 0);
  1311.  
  1312.   if (file->pos + len > *lglen)
  1313.     len = *lglen - file->pos;
  1314.  
  1315.   count = len;
  1316.   while (count)
  1317.     {
  1318.       block b;
  1319.       unsigned long bnum, offs, chunk;
  1320.  
  1321.       bnum  = file->pos / HFS_BLOCKSZ;
  1322.       offs  = file->pos % HFS_BLOCKSZ;
  1323.  
  1324.       chunk = HFS_BLOCKSZ - offs;
  1325.       if (chunk > count)
  1326.     chunk = count;
  1327.  
  1328.       if (f_getblock(file, bnum, &b) < 0)
  1329.     return -1;
  1330.  
  1331.       memcpy(ptr, b + offs, chunk);
  1332.       ptr += chunk;
  1333.  
  1334.       file->pos += chunk;
  1335.       count     -= chunk;
  1336.     }
  1337.  
  1338.   return len;
  1339. }
  1340.  
  1341. /*
  1342.  * NAME:    hfs->write()
  1343.  * DESCRIPTION:    write to an open file
  1344.  */
  1345. long hfs_write(file, buf, len)
  1346.     hfsfile        *file;
  1347.     void        *buf;
  1348.     unsigned long    len;
  1349. {
  1350.   unsigned long *lglen, *pylen, count;
  1351.   unsigned char *ptr = buf;
  1352.  
  1353.   if (file->vol->flags & HFS_READONLY)
  1354.     {
  1355.       ERROR(EROFS, 0);
  1356.       return -1;
  1357.     }
  1358.  
  1359.   f_getptrs(file, &lglen, &pylen, 0);
  1360.  
  1361.   count = len;
  1362.  
  1363.   /* set flag to update (at least) the modification time */
  1364.  
  1365.   if (count)
  1366.     {
  1367.       file->cat.u.fil.filMdDat = d_tomtime(time(0));
  1368.       file->flags |= HFS_UPDATE_CATREC;
  1369.     }
  1370.  
  1371.   while (count)
  1372.     {
  1373.       block b;
  1374.       unsigned long bnum, offs, chunk;
  1375.  
  1376.       bnum  = file->pos / HFS_BLOCKSZ;
  1377.       offs  = file->pos % HFS_BLOCKSZ;
  1378.  
  1379.       chunk = HFS_BLOCKSZ - offs;
  1380.       if (chunk > count)
  1381.     chunk = count;
  1382.  
  1383.       if (file->pos + chunk > *pylen)
  1384.     {
  1385.       if (bt_space(&file->vol->ext, 1) < 0 ||
  1386.           f_alloc(file) < 0)
  1387.         return -1;
  1388.     }
  1389. #ifndef APPLE_HYB
  1390.       /* Ignore this part as we are always writing new files to an empty disk
  1391.      i.e. offs will always be 0 */
  1392.  
  1393.       if (offs > 0 || chunk < HFS_BLOCKSZ)
  1394.     {
  1395.       if (f_getblock(file, bnum, &b) < 0)
  1396.         return -1;
  1397.     }
  1398. #endif /* APPLE_HYB */
  1399.       memcpy(b + offs, ptr, chunk);
  1400.       ptr += chunk;
  1401.  
  1402.       if (f_putblock(file, bnum, &b) < 0)
  1403.     return -1;
  1404.  
  1405.       file->pos += chunk;
  1406.       count     -= chunk;
  1407.  
  1408.       if (file->pos > *lglen)
  1409.     *lglen = file->pos;
  1410.     }
  1411.  
  1412.   return len;
  1413. }
  1414.  
  1415. /*
  1416.  * NAME:    hfs->truncate()
  1417.  * DESCRIPTION:    truncate an open file
  1418.  */
  1419. int hfs_truncate(file, len)
  1420.     hfsfile        *file;
  1421.     unsigned long    len;
  1422. {
  1423.   unsigned long *lglen;
  1424.  
  1425.   f_getptrs(file, &lglen, 0, 0);
  1426.  
  1427.   if (*lglen > len)
  1428.     {
  1429.       if (file->vol->flags & HFS_READONLY)
  1430.     {
  1431.       ERROR(EROFS, 0);
  1432.       return -1;
  1433.     }
  1434.  
  1435.       *lglen = len;
  1436.  
  1437.       file->cat.u.fil.filMdDat = d_tomtime(time(0));
  1438.       file->flags |= HFS_UPDATE_CATREC;
  1439.  
  1440.       if (file->pos > len)
  1441.     file->pos = len;
  1442.     }
  1443.  
  1444.   return 0;
  1445. }
  1446.  
  1447. /*
  1448.  * NAME:    hfs->lseek()
  1449.  * DESCRIPTION:    change file seek pointer
  1450.  */
  1451. long hfs_lseek(file, offset, from)
  1452.     hfsfile    *file;
  1453.     long    offset;
  1454.     int    from;
  1455. {
  1456.   unsigned long *lglen;
  1457.   long newpos;
  1458.  
  1459.   f_getptrs(file, &lglen, 0, 0);
  1460.  
  1461.   switch (from)
  1462.     {
  1463.     case SEEK_SET:
  1464.       newpos = offset;
  1465.       break;
  1466.  
  1467.     case SEEK_CUR:
  1468.       newpos = file->pos + offset;
  1469.       break;
  1470.  
  1471.     case SEEK_END:
  1472.       newpos = *lglen + offset;
  1473.       break;
  1474.  
  1475.     default:
  1476.       ERROR(EINVAL, 0);
  1477.       return -1;
  1478.     }
  1479.  
  1480.   if (newpos < 0)
  1481.     newpos = 0;
  1482.   else if (newpos > *lglen)
  1483.     newpos = *lglen;
  1484.  
  1485.   file->pos = newpos;
  1486.  
  1487.   return newpos;
  1488. }
  1489.  
  1490. /*
  1491.  * NAME:    hfs->close()
  1492.  * DESCRIPTION:    close a file
  1493.  */
  1494. #ifdef APPLE_HYB
  1495. /* extra args are used to set the start of the forks in the ISO volume */
  1496. int hfs_close(file, dext, rext)
  1497.     hfsfile    *file;
  1498.     long    dext;
  1499.     long    rext;
  1500. {
  1501.   int offset;
  1502. #else
  1503. int hfs_close(hfsfile *file)
  1504. {
  1505. #endif /* APPLE_HYB */
  1506.   hfsvol *vol = file->vol;
  1507.   int result = 0;
  1508.  
  1509.   if (f_trunc(file) < 0 ||
  1510.       f_flush(file) < 0)
  1511.     result = -1;
  1512.  
  1513. #ifdef APPLE_HYB
  1514.   /* "start" of file is relative to the first available block */
  1515.   offset = vol->hce->hfs_hdr_size + vol->hce->hfs_map_size;
  1516.   /* update the "real" starting extent and re-flush the file */
  1517.   if (dext)
  1518.     file->cat.u.fil.filExtRec[0].xdrStABN = (dext - offset)/vol->lpa;
  1519.  
  1520.   if (rext)
  1521.     file->cat.u.fil.filRExtRec[0].xdrStABN = (rext - offset)/vol->lpa;
  1522.  
  1523.   if (dext || rext)
  1524.     file->flags |= HFS_UPDATE_CATREC;
  1525.  
  1526.   if (f_flush(file) < 0)
  1527.     result = -1;
  1528. #endif /*APPLE_HYB */
  1529.  
  1530.   if (file->prev)
  1531.     file->prev->next = file->next;
  1532.   if (file->next)
  1533.     file->next->prev = file->prev;
  1534.   if (file == vol->files)
  1535.     vol->files = file->next;
  1536.  
  1537.   FREE(file);
  1538.  
  1539.   return result;
  1540. }
  1541.  
  1542. /* High-Level Catalog Routines ============================================= */
  1543.  
  1544. /*
  1545.  * NAME:    hfs->stat()
  1546.  * DESCRIPTION:    return catalog information for an arbitrary path
  1547.  */
  1548. int hfs_stat(vol, path, ent)
  1549.     hfsvol        *vol;
  1550.     char        *path;
  1551.     hfsdirent    *ent;
  1552. {
  1553.   CatDataRec data;
  1554.   long parid;
  1555.   char name[HFS_MAX_FLEN + 1];
  1556.  
  1557.   if (v_getvol(&vol) < 0 ||
  1558.       v_resolve(&vol, path, &data, &parid, name, 0) <= 0)
  1559.     return -1;
  1560.  
  1561.   r_unpackdirent(parid, name, &data, ent);
  1562.  
  1563.   return 0;
  1564. }
  1565.  
  1566. /*
  1567.  * NAME:    hfs->fstat()
  1568.  * DESCRIPTION:    return catalog information for an open file
  1569.  */
  1570. int hfs_fstat(file, ent)
  1571.     hfsfile        *file;
  1572.     hfsdirent    *ent;
  1573. {
  1574.   r_unpackdirent(file->parid, file->name, &file->cat, ent);
  1575.  
  1576.   return 0;
  1577. }
  1578.  
  1579. /*
  1580.  * NAME:    hfs->setattr()
  1581.  * DESCRIPTION:    change a file's attributes
  1582.  */
  1583. int hfs_setattr(vol, path, ent)
  1584.     hfsvol        *vol;
  1585.     char        *path;
  1586.     hfsdirent    *ent;
  1587. {
  1588.   CatDataRec data;
  1589.   node n;
  1590.  
  1591.   if (v_getvol(&vol) < 0 ||
  1592.       v_resolve(&vol, path, &data, 0, 0, &n) <= 0)
  1593.     return -1;
  1594.  
  1595.   if (vol->flags & HFS_READONLY)
  1596.     {
  1597.       ERROR(EROFS, 0);
  1598.       return -1;
  1599.     }
  1600.  
  1601.   r_packdirent(&data, ent);
  1602.  
  1603.   if (v_putcatrec(&data, &n) < 0)
  1604.     return -1;
  1605.  
  1606.   return 0;
  1607. }
  1608.  
  1609. /*
  1610.  * NAME:    hfs->fsetattr()
  1611.  * DESCRIPTION:    change an open file's attributes
  1612.  */
  1613. int hfs_fsetattr(file, ent)
  1614.     hfsfile        *file;
  1615.     hfsdirent    *ent;
  1616. {
  1617.   if (file->vol->flags & HFS_READONLY)
  1618.     {
  1619.       ERROR(EROFS, 0);
  1620.       return -1;
  1621.     }
  1622.  
  1623.   r_packdirent(&file->cat, ent);
  1624.  
  1625.   file->flags |= HFS_UPDATE_CATREC;
  1626.  
  1627.   return 0;
  1628. }
  1629.  
  1630. /*
  1631.  * NAME:    hfs->mkdir()
  1632.  * DESCRIPTION:    create a new directory
  1633.  */
  1634. int hfs_mkdir(vol, path)
  1635.     hfsvol        *vol;
  1636.     char        *path;
  1637. {
  1638.   CatDataRec data;
  1639.   long parid;
  1640.   char name[HFS_MAX_FLEN + 1];
  1641.   int found;
  1642.  
  1643.   if (v_getvol(&vol) < 0)
  1644.     return -1;
  1645.  
  1646.   found = v_resolve(&vol, path, &data, &parid, name, 0);
  1647.   if (found < 0 || parid == 0)
  1648.     return -1;
  1649.   else if (found)
  1650.     {
  1651.       ERROR(EEXIST, 0);
  1652.       return -1;
  1653.     }
  1654.  
  1655.   if (parid == HFS_CNID_ROOTPAR)
  1656.     {
  1657.       ERROR(EINVAL, 0);
  1658.       return -1;
  1659.     }
  1660.  
  1661.   if (vol->flags & HFS_READONLY)
  1662.     {
  1663.       ERROR(EROFS, 0);
  1664.       return -1;
  1665.     }
  1666.  
  1667.   if (v_newfolder(vol, parid, name) < 0)
  1668.     return -1;
  1669.  
  1670.   return 0;
  1671. }
  1672.  
  1673. /*
  1674.  * NAME:    hfs->rmdir()
  1675.  * DESCRIPTION:    delete an empty directory
  1676.  */
  1677. int hfs_rmdir(vol, path)
  1678.     hfsvol    *vol;
  1679.     char    *path;
  1680. {
  1681.   CatKeyRec key;
  1682.   CatDataRec data;
  1683.   long parid;
  1684.   char name[HFS_MAX_FLEN + 1];
  1685.   unsigned char pkey[HFS_CATKEYLEN];
  1686.  
  1687.   if (v_getvol(&vol) < 0 ||
  1688.       v_resolve(&vol, path, &data, &parid, name, 0) <= 0)
  1689.     return -1;
  1690.  
  1691.   if (data.cdrType != cdrDirRec)
  1692.     {
  1693.       ERROR(ENOTDIR, 0);
  1694.       return -1;
  1695.     }
  1696.  
  1697.   if (data.u.dir.dirVal != 0)
  1698.     {
  1699.       ERROR(ENOTEMPTY, 0);
  1700.       return -1;
  1701.     }
  1702.  
  1703.   if (parid == HFS_CNID_ROOTPAR)
  1704.     {
  1705.       ERROR(EINVAL, 0);
  1706.       return -1;
  1707.     }
  1708.  
  1709.   if (vol->flags & HFS_READONLY)
  1710.     {
  1711.       ERROR(EROFS, 0);
  1712.       return -1;
  1713.     }
  1714.  
  1715.   /* delete directory record */
  1716.  
  1717.   r_makecatkey(&key, parid, name);
  1718.   r_packcatkey(&key, pkey, 0);
  1719.  
  1720.   if (bt_delete(&vol->cat, pkey) < 0)
  1721.     return -1;
  1722.  
  1723.   /* delete thread record */
  1724.  
  1725.   r_makecatkey(&key, data.u.dir.dirDirID, "");
  1726.   r_packcatkey(&key, pkey, 0);
  1727.  
  1728.   if (bt_delete(&vol->cat, pkey) < 0 ||
  1729.       v_adjvalence(vol, parid, 1, -1) < 0)
  1730.     return -1;
  1731.  
  1732.   return 0;
  1733. }
  1734.  
  1735. /*
  1736.  * NAME:    hfs->create()
  1737.  * DESCRIPTION:    create a new file
  1738.  */
  1739. int hfs_create(vol, path, type, creator)
  1740.     hfsvol    *vol;
  1741.     char    *path;
  1742.     char    *type;
  1743.     char    *creator;
  1744. {
  1745.   CatKeyRec key;
  1746.   CatDataRec data;
  1747.   long id, parid;
  1748.   char name[HFS_MAX_FLEN + 1];
  1749.   unsigned char record[HFS_CATRECMAXLEN];
  1750.   int found, i, reclen;
  1751.  
  1752.   if (v_getvol(&vol) < 0)
  1753.     return -1;
  1754.  
  1755.   found = v_resolve(&vol, path, &data, &parid, name, 0);
  1756.   if (found < 0 || parid == 0)
  1757.     return -1;
  1758.   else if (found)
  1759.     {
  1760.       ERROR(EEXIST, 0);
  1761.       return -1;
  1762.     }
  1763.  
  1764.   if (parid == HFS_CNID_ROOTPAR)
  1765.     {
  1766.       ERROR(EINVAL, 0);
  1767.       return -1;
  1768.     }
  1769.  
  1770.   if (vol->flags & HFS_READONLY)
  1771.     {
  1772.       ERROR(EROFS, 0);
  1773.       return -1;
  1774.     }
  1775.  
  1776.   /* create file `name' in parent `parid' */
  1777.  
  1778.   if (bt_space(&vol->cat, 1) < 0)
  1779.     return -1;
  1780.  
  1781.   id = vol->mdb.drNxtCNID++;
  1782.   vol->flags |= HFS_UPDATE_MDB;
  1783.  
  1784.   /* create file record */
  1785.  
  1786.   data.cdrType   = cdrFilRec;
  1787.   data.cdrResrv2 = 0;
  1788.  
  1789.   data.u.fil.filFlags = 0;
  1790.   data.u.fil.filTyp   = 0;
  1791.  
  1792.   memset(&data.u.fil.filUsrWds, 0, sizeof(data.u.fil.filUsrWds));
  1793.  
  1794.   data.u.fil.filUsrWds.fdType    = d_getl((unsigned char *) type);
  1795.   data.u.fil.filUsrWds.fdCreator = d_getl((unsigned char *) creator);
  1796.  
  1797.   data.u.fil.filFlNum  = id;
  1798.   data.u.fil.filStBlk  = 0;
  1799.   data.u.fil.filLgLen  = 0;
  1800.   data.u.fil.filPyLen  = 0;
  1801.   data.u.fil.filRStBlk = 0;
  1802.   data.u.fil.filRLgLen = 0;
  1803.   data.u.fil.filRPyLen = 0;
  1804.   data.u.fil.filCrDat  = d_tomtime(time(0));
  1805.   data.u.fil.filMdDat  = data.u.fil.filCrDat;
  1806.   data.u.fil.filBkDat  = 0;
  1807.  
  1808.   memset(&data.u.fil.filFndrInfo, 0, sizeof(data.u.fil.filFndrInfo));
  1809.  
  1810.   data.u.fil.filClpSize = 0;
  1811.  
  1812.   for (i = 0; i < 3; ++i)
  1813.     {
  1814.       data.u.fil.filExtRec[i].xdrStABN     = 0;
  1815.       data.u.fil.filExtRec[i].xdrNumABlks  = 0;
  1816.  
  1817.       data.u.fil.filRExtRec[i].xdrStABN    = 0;
  1818.       data.u.fil.filRExtRec[i].xdrNumABlks = 0;
  1819.     }
  1820.  
  1821.   data.u.fil.filResrv = 0;
  1822.  
  1823.   r_makecatkey(&key, parid, name);
  1824.   r_packcatkey(&key, record, &reclen);
  1825.   r_packcatdata(&data, HFS_RECDATA(record), &reclen);
  1826.  
  1827.   if (bt_insert(&vol->cat, record, reclen) < 0 ||
  1828.       v_adjvalence(vol, parid, 0, 1) < 0)
  1829.     return -1;
  1830.  
  1831.   return 0;
  1832. }
  1833.  
  1834. /*
  1835.  * NAME:    hfs->delete()
  1836.  * DESCRIPTION:    remove both forks of a file
  1837.  */
  1838. int hfs_delete(vol, path)
  1839.     hfsvol    *vol;
  1840.     char    *path;
  1841. {
  1842.   hfsfile file;
  1843.   CatKeyRec key;
  1844.   unsigned char pkey[HFS_CATKEYLEN];
  1845.   int found;
  1846.  
  1847.   if (v_getvol(&vol) < 0 ||
  1848.       v_resolve(&vol, path, &file.cat, &file.parid, file.name, 0) <= 0)
  1849.     return -1;
  1850.  
  1851.   if (file.cat.cdrType != cdrFilRec)
  1852.     {
  1853.       ERROR(EISDIR, 0);
  1854.       return -1;
  1855.     }
  1856.  
  1857.   if (file.parid == HFS_CNID_ROOTPAR)
  1858.     {
  1859.       ERROR(EINVAL, 0);
  1860.       return -1;
  1861.     }
  1862.  
  1863.   if (vol->flags & HFS_READONLY)
  1864.     {
  1865.       ERROR(EROFS, 0);
  1866.       return -1;
  1867.     }
  1868.  
  1869.   /* free disk blocks */
  1870.  
  1871.   file.vol   = vol;
  1872.   file.flags = 0;
  1873.  
  1874.   file.cat.u.fil.filLgLen  = 0;
  1875.   file.cat.u.fil.filRLgLen = 0;
  1876.  
  1877.   f_selectfork(&file, 0);
  1878.   if (f_trunc(&file) < 0)
  1879.     return -1;
  1880.  
  1881.   f_selectfork(&file, 1);
  1882.   if (f_trunc(&file) < 0)
  1883.     return -1;
  1884.  
  1885.   /* delete file record */
  1886.  
  1887.   r_makecatkey(&key, file.parid, file.name);
  1888.   r_packcatkey(&key, pkey, 0);
  1889.  
  1890.   if (bt_delete(&vol->cat, pkey) < 0 ||
  1891.       v_adjvalence(vol, file.parid, 0, -1) < 0)
  1892.     return -1;
  1893.  
  1894.   /* delete file thread, if any */
  1895.  
  1896.   found = v_getfthread(vol, file.cat.u.fil.filFlNum, 0, 0);
  1897.   if (found < 0)
  1898.     return -1;
  1899.  
  1900.   if (found)
  1901.     {
  1902.       r_makecatkey(&key, file.cat.u.fil.filFlNum, "");
  1903.       r_packcatkey(&key, pkey, 0);
  1904.  
  1905.       if (bt_delete(&vol->cat, pkey) < 0)
  1906.     return -1;
  1907.     }
  1908.  
  1909.   return 0;
  1910. }
  1911.  
  1912. /*
  1913.  * NAME:    hfs->rename()
  1914.  * DESCRIPTION:    change the name of and/or move a file or directory
  1915.  */
  1916. int hfs_rename(vol, srcpath, dstpath)
  1917.     hfsvol    *vol;
  1918.     char    *srcpath;
  1919.     char    *dstpath;
  1920. {
  1921.   hfsvol *srcvol;
  1922.   CatDataRec src, dst;
  1923.   long srcid, dstid;
  1924.   CatKeyRec key;
  1925.   char srcname[HFS_MAX_FLEN + 1], dstname[HFS_MAX_FLEN + 1];
  1926.   unsigned char record[HFS_CATRECMAXLEN];
  1927.   int found, isdir, moving, reclen;
  1928.   node n;
  1929.  
  1930.   if (v_getvol(&vol) < 0 ||
  1931.       v_resolve(&vol, srcpath, &src, &srcid, srcname, 0) <= 0)
  1932.     return -1;
  1933.  
  1934.   isdir  = (src.cdrType == cdrDirRec);
  1935.   srcvol = vol;
  1936.  
  1937.   found = v_resolve(&vol, dstpath, &dst, &dstid, dstname, 0);
  1938.   if (found < 0)
  1939.     return -1;
  1940.  
  1941.   if (vol != srcvol)
  1942.     {
  1943.       ERROR(EINVAL, "can't move across volumes");
  1944.       return -1;
  1945.     }
  1946.  
  1947.   if (dstid == 0)
  1948.     {
  1949.       ERROR(ENOENT, "bad destination path");
  1950.       return -1;
  1951.     }
  1952.  
  1953.   if (found &&
  1954.       dst.cdrType == cdrDirRec &&
  1955.       dst.u.dir.dirDirID != src.u.dir.dirDirID)
  1956.     {
  1957.       dstid = dst.u.dir.dirDirID;
  1958.       strcpy(dstname, srcname);
  1959.  
  1960.       found = v_catsearch(vol, dstid, dstname, 0, 0, 0);
  1961.       if (found < 0)
  1962.     return -1;
  1963.     }
  1964.  
  1965.   moving = (srcid != dstid);
  1966.  
  1967.   if (found)
  1968.     {
  1969.       char *ptr;
  1970.  
  1971.       ptr = strrchr(dstpath, ':');
  1972.       if (ptr == 0)
  1973.     ptr = dstpath;
  1974.       else
  1975.     ++ptr;
  1976.  
  1977.       if (*ptr)
  1978.     strcpy(dstname, ptr);
  1979.  
  1980.       if (! moving && strcmp(srcname, dstname) == 0)
  1981.     return 0;  /* source and destination are the same */
  1982.  
  1983.       if (moving || d_relstring(srcname, dstname))
  1984.     {
  1985.       ERROR(EEXIST, "can't use destination name");
  1986.       return -1;
  1987.     }
  1988.     }
  1989.  
  1990.   /* can't move anything into the root directory's parent */
  1991.  
  1992.   if (moving && dstid == HFS_CNID_ROOTPAR)
  1993.     {
  1994.       ERROR(EINVAL, "can't move above root directory");
  1995.       return -1;
  1996.     }
  1997.  
  1998.   if (moving && isdir)
  1999.     {
  2000.       long id;
  2001.  
  2002.       /* can't move root directory anywhere */
  2003.  
  2004.       if (src.u.dir.dirDirID == HFS_CNID_ROOTDIR)
  2005.     {
  2006.       ERROR(EINVAL, "can't move root directory");
  2007.       return -1;
  2008.     }
  2009.  
  2010.       /* make sure we aren't trying to move a directory inside itself */
  2011.  
  2012.       for (id = dstid; id != HFS_CNID_ROOTDIR; id = dst.u.dthd.thdParID)
  2013.     {
  2014.       if (id == src.u.dir.dirDirID)
  2015.         {
  2016.           ERROR(EINVAL, "can't move directory inside itself");
  2017.           return -1;
  2018.         }
  2019.  
  2020.       if (v_getdthread(vol, id, &dst, 0) <= 0)
  2021.         return -1;
  2022.     }
  2023.     }
  2024.  
  2025.   if (vol->flags & HFS_READONLY)
  2026.     {
  2027.       ERROR(EROFS, 0);
  2028.       return -1;
  2029.     }
  2030.  
  2031.   /* change volume name */
  2032.  
  2033.   if (dstid == HFS_CNID_ROOTPAR)
  2034.     {
  2035.       if (strlen(dstname) > HFS_MAX_VLEN)
  2036.     {
  2037.       ERROR(ENAMETOOLONG, 0);
  2038.       return -1;
  2039.     }
  2040.  
  2041.       strcpy(vol->mdb.drVN, dstname);
  2042.       vol->flags |= HFS_UPDATE_MDB;
  2043.     }
  2044.  
  2045.   /* remove source record */
  2046.  
  2047.   r_makecatkey(&key, srcid, srcname);
  2048.   r_packcatkey(&key, record, 0);
  2049.  
  2050.   if (bt_delete(&vol->cat, record) < 0)
  2051.     return -1;
  2052.  
  2053.   /* insert destination record */
  2054.  
  2055.   r_makecatkey(&key, dstid, dstname);
  2056.   r_packcatkey(&key, record, &reclen);
  2057.   r_packcatdata(&src, HFS_RECDATA(record), &reclen);
  2058.  
  2059.   if (bt_insert(&vol->cat, record, reclen) < 0)
  2060.     return -1;
  2061.  
  2062.   /* update thread record */
  2063.  
  2064.   if (isdir)
  2065.     {
  2066.       if (v_getdthread(vol, src.u.dir.dirDirID, &dst, &n) <= 0)
  2067.     return -1;
  2068.  
  2069.       dst.u.dthd.thdParID = dstid;
  2070.       strcpy(dst.u.dthd.thdCName, dstname);
  2071.  
  2072.       if (v_putcatrec(&dst, &n) < 0)
  2073.     return -1;
  2074.     }
  2075.   else
  2076.     {
  2077.       found = v_getfthread(vol, src.u.fil.filFlNum, &dst, &n);
  2078.       if (found < 0)
  2079.     return -1;
  2080.  
  2081.       if (found)
  2082.     {
  2083.       dst.u.fthd.fthdParID = dstid;
  2084.       strcpy(dst.u.fthd.fthdCName, dstname);
  2085.  
  2086.       if (v_putcatrec(&dst, &n) < 0)
  2087.         return -1;
  2088.     }
  2089.     }
  2090.  
  2091.   /* update directory valences */
  2092.  
  2093.   if (moving)
  2094.     {
  2095.       if (v_adjvalence(vol, srcid, isdir, -1) < 0 ||
  2096.       v_adjvalence(vol, dstid, isdir,  1) < 0)
  2097.     return -1;
  2098.     }
  2099.  
  2100.   return 0;
  2101. }
  2102. #ifdef APPLE_HYB
  2103. /*
  2104.  * NAME:        hfs->hfs_get_drAllocPtr()
  2105.  * DESCRIPTION: get the current start of next allocation search 
  2106.  */
  2107. unsigned short
  2108. hfs_get_drAllocPtr(file)
  2109.     hfsfile    *file;
  2110. {
  2111.   return(file->vol->mdb.drAllocPtr);
  2112. }
  2113.  
  2114. /*
  2115.  * NAME:        hfs->hfs_set_drAllocPtr()
  2116.  * DESCRIPTION: set the current start of next allocation search 
  2117.  */
  2118. #ifdef    PROTOTYPES
  2119. int
  2120. hfs_set_drAllocPtr(hfsfile *file, unsigned short drAllocPtr, int size)
  2121. #else
  2122. int
  2123. hfs_set_drAllocPtr(file, drAllocPtr, size)
  2124.     hfsfile        *file;
  2125.     unsigned short    drAllocPtr;
  2126.     int        size;
  2127. #endif
  2128. {
  2129.   hfsvol *vol = file->vol;
  2130.   int result = 0;
  2131.  
  2132.   /* truncate the current fork */
  2133.   if (f_trunc(file) < 0 ||
  2134.       f_flush(file) < 0)
  2135.     result = -1;
  2136.  
  2137.   /* convert the fork size into allocation blocks */
  2138.   size = (size + vol->mdb.drAlBlkSiz - 1)/vol->mdb.drAlBlkSiz;
  2139.  
  2140.   /* set the start of next allocation search to be after this fork */
  2141.   vol->mdb.drAllocPtr = drAllocPtr + size;
  2142.  
  2143.   vol->flags |= HFS_UPDATE_MDB;
  2144.  
  2145.   return result;
  2146. }
  2147. #endif /* APPLE_HYB */
  2148.